﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;

namespace Jemgine.Engine.Scripts
{
    [Category("Physics"), Component]
   public class ApplyBuoyancy: Jemgine.Engine.EntityComponent, Jemgine.Data.Rotatable, Jemgine.Data.EditorDrawable
    {   
        [ContentSerializer(Optional = true)]
        public float SurfaceAngle { get; set; }

        public float LiquidDensity { get; set; }
        public float LiquidLinearDrag { get; set; }
        public float LiquidAngularDrag { get; set; }


       public ApplyBuoyancy()
       {
           AddInput("Fire", typeof(Physics));
           AddOutput("Relay", null);
           LiquidDensity = 1;
           LiquidLinearDrag = 2;
           LiquidAngularDrag = 80;
       }

       public override void FireTerminal(int InputID, Data.ScriptPayload Payload)
       {
           if (Payload.Physics != null && !Jemgine.Math.Utility.AlmostZero(LiquidDensity))
           {
               var Body = Payload.Physics.PhysicsBody;

               //if (Body.IsAwake())
               //{
                   var SurfacePointA = Position + Vector2.Transform(new Vector2(0, 8),
                        Matrix.CreateRotationZ(SurfaceAngle + (float)(System.Math.PI / 2)));
                   var SurfacePointB = Position + Vector2.Transform(new Vector2(0, 8),
                        Matrix.CreateRotationZ(SurfaceAngle - (float)(System.Math.PI / 2)));

                   var ParentTransform = (Me == null ? Matrix.Identity : Me.GetTransform());
                   SurfacePointA = Vector2.Transform(SurfacePointA, ParentTransform);
                   SurfacePointB = Vector2.Transform(SurfacePointB, ParentTransform);

                   var SurfacePerpPoint = Jemgine.Math.Intersection.ClosestPointOnLineToPoint(
                       SurfacePointA, SurfacePointB, Body.Position);

                   var PenetrationDepth = (SurfacePerpPoint - Body.Position).Length();

                   var BuoyancyForce = -Payload.Physics.Gravity * PenetrationDepth * LiquidDensity;

                   Body.ApplyLinearImpulse(BuoyancyForce, Body.Position);

                   var DragForce = Body.GetLinearVelocityFromWorldPoint(
                       Body.Position); //Somehow calculate a point below the surface of the fluid? Contact 
                   //point from sensor, possibly?
                   DragForce *= -LiquidLinearDrag;
                   Body.ApplyLinearImpulse(DragForce, Body.Position + Vector2.Normalize(Payload.Physics.Gravity));

                   var T = Body.GetAngularVelocity() * LiquidAngularDrag;
                   if (!Jemgine.Math.Utility.AlmostZero(T))
                       Body.ApplyAngularImpulse(-T);
               //}
           }

           OutputTerminals[0].Fire(Payload);
       }


       #region Rotatable Members

       object Jemgine.Data.Rotatable.PrepareToRotate()
       {
           return SurfaceAngle;
       }

       void Jemgine.Data.Rotatable.ApplyRotation(object Tag, float Rotation)
       {
           float OriginalAngle = (float)Tag;
           SurfaceAngle = Jemgine.Math.Angle.Normalize(OriginalAngle + Rotation);
       }

       void Jemgine.Data.Rotatable.Snap(Jemgine.Data.Snapper Snapper)
       {
           SurfaceAngle = Jemgine.Math.Angle.Normalize(Snapper.SnapRotation(SurfaceAngle));
       }

       #endregion

       #region EditorDrawable Members

       void Jemgine.Data.EditorDrawable.Draw(int ID, Jemgine.Data.EditorDrawData Context, Jemgine.Data.SelectionType Selected)
       {
           base.Draw(ID, Context, Selected);

           if (Selected == Jemgine.Data.SelectionType.Selected || Selected == Jemgine.Data.SelectionType.WorkingSet)
           {
               Context.Renderer.Color = Color.Gold.ToVector4();

               Context.Renderer.DrawLine(Position,
                   Position + Vector2.Transform(new Vector2(0, 8), 
                        Matrix.CreateRotationZ(SurfaceAngle + (float)(System.Math.PI / 2))),
                   0.2f);

               Context.Renderer.DrawLine(Position,
                   Position + Vector2.Transform(new Vector2(0, 8),
                        Matrix.CreateRotationZ(SurfaceAngle - (float)(System.Math.PI / 2))),
                   0.2f);

               Context.Renderer.Color = Color.Green.ToVector4();

               Context.Renderer.DrawLine(Position,
                   Position + Vector2.Transform(new Vector2(0, 4),
                        Matrix.CreateRotationZ(SurfaceAngle)),
                   0.2f);
           }
       }

       #endregion
    }
}
